{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n    @Author: King\\n    @Date: 2019.06.25\\n    @Purpose: Builtin message passing functions\\n    @Introduction:   \\n    @Datasets: \\n    @Link : \\n    @Reference : https://docs.dgl.ai/features/builtin.html\\n'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''\n",
    "    @Author: King\n",
    "    @Date: 2019.06.25\n",
    "    @Purpose: Builtin message passing functions\n",
    "    @Introduction:   \n",
    "    @Datasets: \n",
    "    @Link : \n",
    "    @Reference : https://docs.dgl.ai/features/builtin.html\n",
    "'''"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Builtin message passing functions\n",
    "\n",
    "In DGL, message passing(消息传递) is expressed by two APIs:\n",
    "\n",
    "- send(edges, message_func) for computing the messages along the given edges.\n",
    "- recv(nodes, reduce_func) for collecting the in-coming messages, perform aggregation and so on.\n",
    "\n",
    "Although the two-stage abstraction can cover all the models that are defined in the message passing paradigm, it is inefficient due to storing explicit messages. See our blogpost for more details and performance results.\n",
    "\n",
    "Our solution, also explained in the blogpost, is to fuse the two stages into one kernel so no explicit messages are generated and stored. To achieve this, we recommend using our builtin message/reduce functions so that DGL can analyze and map them to fused dedicated kernels. （我们的解决方案，也在博文中解释，是将两个阶段融合到一个内核中，因此不会生成和存储显式消息。为此，我们建议使用内置的message / reduce函数，以便DGL可以分析并将它们映射到融合的专用内核。）\n",
    "\n",
    "Here are some examples (in pytorch syntax):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "module 'dgl.function' has no attribute 'copy_u'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-6-55f63edf27e2>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[0mg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0medata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'w'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mth\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnumber_of_edges\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# each edge has feature size 1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m \u001b[1;31m# collect features from source nodes and aggregate them in destination nodes\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate_all\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcopy_u\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'h'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'm'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'm'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'h_sum'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      9\u001b[0m \u001b[1;31m# multiply source node features with edge weights and aggregate them in destination nodes\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[0mg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate_all\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mu_mul_e\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'h'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'w'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'm'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmax\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'm'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'h_max'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mAttributeError\u001b[0m: module 'dgl.function' has no attribute 'copy_u'"
     ]
    }
   ],
   "source": [
    "import dgl\n",
    "import dgl.function as fn\n",
    "import torch as th\n",
    "g =  dgl.DGLGraph() # create a DGLGraph\n",
    "g.ndata['h'] = th.randn((g.number_of_nodes(), 10)) # each node has feature size 10\n",
    "g.edata['w'] = th.randn((g.number_of_edges(), 1))  # each edge has feature size 1\n",
    "# collect features from source nodes and aggregate them in destination nodes\n",
    "g.update_all(fn.copy_u('h', 'm'), fn.sum('m', 'h_sum'))\n",
    "# multiply source node features with edge weights and aggregate them in destination nodes\n",
    "g.update_all(fn.u_mul_e('h', 'w', 'm'), fn.max('m', 'h_max'))\n",
    "# compute edge embedding by multiplying source and destination node embeddings\n",
    "g.apply_edges(fn.u_mul_v('h', 'h', 'w_new'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
